using System.IO;
using System.Text;
using NFreeMarker.Template;

namespace NFreeMarker.Core
{
    public sealed class StringLiteral : Expression, ITemplateScalarModel // NOTE: Was internal
    {
        private readonly string _value;
        private TemplateElement _interpolatedOutput;

        internal StringLiteral(string value)
        {
            _value = value;
        }

        internal void CheckInterpolation()
        {
            if (_value.Length <= 3 || (_value.IndexOf("${") < 0 && _value.IndexOf("#{") < 0))
            {
                return;
            }

            var scs = new SimpleCharStream(new StringReader(_value), BeginLine, BeginColumn+1, _value.Length);
            var tokenSource = new FMParserTokenManager(scs)
            {
                onlyTextOutput = true
            };
            var parser = new FMParser(tokenSource)
            {
                template = GetTemplate()
            };
            try
            {
                _interpolatedOutput = parser.FreeMarkerText();
            }
            catch(ParseException e)
            {
                e.SetTemplateName(GetTemplate().GetName());
                throw;
            }
            ConstantValue = null;
        }

        protected override ITemplateModel _getAsTemplateModel(Environment env)
        {
            return new SimpleScalar(GetStringValue(env));
        }

        public string GetAsString()
        {
            return _value;
        }

        internal override string GetStringValue(Environment env)
        {
            if (_interpolatedOutput == null)
            {
                return _value;
            }
            
            ITemplateExceptionHandler teh = env.GetTemplateExceptionHandler();
            env.SetTemplateExceptionHandler(TemplateExceptionHandler.RethrowHandler);
            try
            {
                return env.RenderElementToString(_interpolatedOutput);
            }
            catch (IOException ioe)
            {
                throw new TemplateException(ioe, env);
            }
            finally
            {
                env.SetTemplateExceptionHandler(teh);
            }
        }

        public override string GetCanonicalForm()
        {
    //        return "\"" + StringUtil.FTLStringLiteralEnc(value) + "\""; 
            return "\"" + EscapeString(_value) + "\"";
        }

        internal override bool IsLiteral()
        {
            return _interpolatedOutput == null;
        }

        protected override Expression DeepCloneImpl(string name, Expression subst)
        {
            var cloned = new StringLiteral(_value)
            {
                _interpolatedOutput = _interpolatedOutput
            };
            return cloned;
        }

        // TODO: Test this
        static private string EscapeString(string s)
        {
            if (s.IndexOf('"') == -1)
            {
                return s;
            }

            var buf = new StringBuilder();

            string[] strings = s.Split('\"');
            for (int i = 0; i < strings.Length; i++)
            {
                string st = strings[i];
                buf.Append(st);
                if (i != strings.Length - 1)
                {
                    buf.Append("\\\"");
                }
            }

            return buf.ToString();
        }
    }
}